﻿using EWSEditor.Forms;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EWSEditor.CRM.Forms
{
    public partial class EmailValidatorForm : Form
    {
        private EmailMessage _email;

        public EmailMessage Email
        {
            get { return _email; }
            set { _email = value; }
        }

        private CheckIncomingEmailRequest _checkRequest;
        private CheckIncomingEmailResponse _checkResponse;

        public bool UsedExtraProperties
        {
            get { return _usedExtraProperties; }
            set { _usedExtraProperties = value; }
        }

        private bool _usedExtraProperties;

        public EmailValidatorForm(EmailMessage email)
        {
            InitializeComponent();
            _email = email;
            this.Text = "Validation Result: " + email.Subject;
            rtbInformation.ReadOnly = true;
            DetermineExtraProperties();
            Thread checkincomingemailthread = new Thread(new ThreadStart(PerformCheckIncomingEmailRequest));
            checkincomingemailthread.SetApartmentState(ApartmentState.STA);
            checkincomingemailthread.Start();
        }

        private void DetermineExtraProperties()
        {
            if ((OptionSetValue)CrmOrgMailboxCache.Organization["emailconnectionchannel"] == new OptionSetValue(0) && (OptionSetValue)CrmOrgMailboxCache.TargetMailbox["incomingemaildeliverymethod"] == new OptionSetValue(2)
                || (OptionSetValue)CrmOrgMailboxCache.TargetMailbox["incomingemaildeliverymethod"] == new OptionSetValue(3))
            {
                UsedExtraProperties = true;
            }
            UsedExtraProperties = false;

        }

        private void PerformCheckIncomingEmailRequest()
        {
            try
            {
                CheckIncomingEmailRequest checkrequest = new CheckIncomingEmailRequest();
                checkrequest.Bcc = GetAddresses(_email.BccRecipients);
                checkrequest.Cc = GetAddresses(_email.CcRecipients);
                checkrequest.From = _email.From.Address;
                checkrequest.MessageId = _email.InternetMessageId;
                checkrequest.Subject = _email.Subject;
                checkrequest.To = GetAddresses(_email.ToRecipients);
                if (UsedExtraProperties)
                {
                    checkrequest.ExtraProperties = ConversationIndexUtility.GetExtraProperties(_email);
                }

                OrganizationServiceProxy orgProxy = CrmAuthInfoFactory.GetOrgProxy();

                _checkRequest = checkrequest;
                _checkResponse = (CheckIncomingEmailResponse)orgProxy.Execute(checkrequest);

                this.Invoke(new Action(SetFormProperties));
            }

            catch (Exception ex)
            {
                this.Invoke(new Action<Exception>(DisplayError), ex);
            }
        }

        private void DisplayError(Exception ex)
        {
            //Need to update this with a better error messaging mechanism...
            MessageBox.Show(ex.StackTrace, ex.Message);
        }

        private string GetAddresses(EmailAddressCollection recipients)
        {
            StringBuilder addresses = new StringBuilder();
            foreach (var recipient in recipients)
            {
                addresses.Append(recipient.Address);
                addresses.Append(";");
            }
            return addresses.ToString();
        }

        private void SetFormProperties()
        {
            lblPromoteValue.Text = _checkResponse.ShouldDeliver.ToString();
            ValidationReasonCode code = (ValidationReasonCode)_checkResponse.ReasonCode;
            lblReasonCodeValue.Text = code.ToString();
            switch (code)
            {
                case ValidationReasonCode.Unknown:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("Unknown", code);
                    break;

                case ValidationReasonCode.Duplicate:
                    PopulateRTB("This e-mail message has already been promoted to Dynamics 365.", code);
                    break;

                case ValidationReasonCode.NoCorrelationMatch:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("Correlation was attempted but did not map to a prior Dynamics 365 message.", code);
                    break;

                case ValidationReasonCode.CorrelationMatch:
                    PopulateRTB("Correlation was attempted and found a qualifying message for promotion.", code);
                    break;

                case ValidationReasonCode.NoRecipientMatch:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("None of the recipients of the e-mail are users or queues in Dynamics 365", code);
                    break;

                case ValidationReasonCode.InternalEmailReject:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("E-mail is considered internal communication between users or queues.", code);
                    break;

                case ValidationReasonCode.SenderMatch:
                    PopulateRTB("E-mail was accepted because a recipient is configured to promote e-mails received from the sender.", code);
                    break;

                case ValidationReasonCode.AcceptAll:
                    PopulateRTB("Email was accepted because a recipient accepts all emails.", code);
                    break;

                case ValidationReasonCode.InvalidSender:
                    //promoteBtn.IsEnabled = true;
                    PopulateRTB("The sender email address could not be found or is invalid", code);
                    break;

            }
        }

        private void PopulateRTB(string message, ValidationReasonCode code)
        {
            rtbInformation.Text = message;
            if (!UsedExtraProperties && code == ValidationReasonCode.NoCorrelationMatch)
            {
                rtbInformation.AppendText("\n\nEmail correlation did not use In-Reply-To or ConversationIndex. To attempt correlation using these properties, switch to Server Side Synchronization and try again."); 
            }
            rtbInformation.AppendText("\n\nRequest Properties:\n\n");
            rtbInformation.AppendText(BuildProperties());
            rtbInformation.ScrollBars = RichTextBoxScrollBars.Vertical;
            
        }

        private string BuildProperties()
        {
            StringBuilder properties = new StringBuilder();
            properties.Append("Subject:  ").Append(_checkRequest.Subject).Append("\n");
            properties.Append("To:  ").Append(_checkRequest.To).Append("\n");
            properties.Append("From: ").Append(_checkRequest.From).Append("\n");
            properties.Append("CC: ").Append(_checkRequest.Cc).Append("\n");
            properties.Append("BCC: ").Append(_checkRequest.Bcc).Append("\n");
            properties.Append("MessageId: ").Append(_checkRequest.MessageId).Append("\n");
            if (UsedExtraProperties)
            {
                if (_checkRequest.ExtraProperties.Attributes.ContainsKey("conversationindex"))
                {
                    properties.Append("ConversationIndex: ").Append(_checkRequest.ExtraProperties.Attributes["conversationindex"]).Append("\n");
                }
                if (_checkRequest.ExtraProperties.Attributes.ContainsKey("inreplyto"))
                {
                    properties.Append("In-Reply-To: ").Append(_checkRequest.ExtraProperties.Attributes["inreplyto"]).Append("\n");
                }
            }
            return properties.ToString();
        }


        private void lblPromoteValue_Click(object sender, EventArgs e)
        {

        }

        public enum ValidationReasonCode
        {
            Unknown = -1,
            Duplicate = 0,
            NoCorrelationMatch = 1,
            CorrelationMatch = 2,
            NoRecipientMatch = 3,
            InternalEmailReject = 4,
            SenderMatch = 5,
            AcceptAll = 6,
            InvalidSender = 7
        }

    }
}
